/*
 * Copyright (C) 2013 Daniel Wasilew <daniel.wasilew@codeminer.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.codeminer.parts.specification;

import de.wusel.picotask.xml.XMLImportSupport;
import de.wusel.picotask.xml.element.XMLElement;
import org.codeminer.parts.files.FileUtil;
import org.codeminer.parts.specification.html.HTMLDocumentationCreator;
import org.codeminer.parts.specification.source.ActionFactoryCreator;
import org.codeminer.parts.specification.source.JavaFileCreator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileFilter;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Daniel Wasilew <daniel.wasilew@codeminer.org>
 */
public class Parser {

    private static final Logger log = LoggerFactory.getLogger(Parser.class);
    private final List<DocCreator> docCreators = new LinkedList<>();
    private final ParserFileLocations locations;

    public Parser(ParserFileLocations locations) {
        this.docCreators.add(new JavaFileCreator(locations));
        this.docCreators.add(new ActionFactoryCreator(locations));
        this.docCreators.add(new HTMLDocumentationCreator(locations));
        this.locations = locations;
    }

    public static void main(String[] args) throws CreationException {

        Parser parser = new Parser(new ParserFileLocations() {

            @Override
            public File getSpecificationDirectory() {
                return new File(getProjectMainDir(), "src/main/specification/socket-entry");
            }

            @Override
            public File getJavaSourceOutputDirectory() {
                File projectMainDir = getProjectMainDir();
                return new File(projectMainDir, "src/main/java/org/codeminer/parts/server/actions/");
            }

            @Override
            public File getHTMLDocumentationOutputDirectory() {
                File projectMainDir = getProjectMainDir();
                return new File(projectMainDir, "src/main/resources/documents");
            }

            @Override
            public boolean alwaysRecreate() {
                return false;
            }

            private File getProjectMainDir() {
                try {
                    File jarFile = new File(Parser.class.getProtectionDomain().getCodeSource().getLocation().toURI());
                    return jarFile.getParentFile().getParentFile();
                } catch (URISyntaxException ex) {
                    log.error("could not get specificationDirectory", ex);
                    return null;
                }
            }
        });
        parser.parse();
    }

    void parse() throws CreationException {
        log.info("trying to parse xml specifications");
        File specDirectory = locations.getSpecificationDirectory();
        if (specDirectory.exists()) {
            parseDirectory(specDirectory);
        } else {
            log.error("[" + specDirectory + "] does not exist");
        }
    }

    private void parseDirectory(File specDirectory) throws CreationException {
        log.info("parsing directory [{}]", specDirectory.getAbsolutePath());
        for (DocCreator docCreator : docCreators) {
            docCreator.start();
        }


        List<File> allSpecFiles = FileUtil.traverseDirectory(specDirectory, new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getAbsolutePath().endsWith(".xml");
            }
        });
        for (File file : allSpecFiles) {
            try {
                parseSpecFile(file);
            } catch (Exception ex) {
                log.error("could not create class for [" + file + "]", ex);
            }
        }
        for (DocCreator docCreator : docCreators) {
            docCreator.end();
        }
    }

    private void parseSpecFile(File file) throws CreationException {
        log.info("parsing [{}] spec file", file.getName());
        XMLElement element = XMLImportSupport.parseFile(file);
        for (DocCreator docCreator : docCreators) {
            docCreator.create(element, file);
        }
    }
}
